# 算术运算符是处理四则运算的符号，在数字的处理中应用得最多。Python 支持所有的基本算术运算符
#
# 运算符	说明	实例	结果
# +	    加	12.45 + 15	27.45
# - 	减	4.56 - 0.26	4.3
# *	    乘	5 * 3.6	18.0
# /	    除	7 / 2	3.5
# %	    取余，即返回除法的余数	7 % 2	1
# //	整除，返回商的整数部分	7 // 2	3
# **	幂，即返回 x 的 y 次方	2 ** 4	16，即 24

# + 加法运算符
import time

x = 1
y = 2
print(x + y)

# 除此以外， + 可以作为字符串的连接运算符
s1 = "Hello"
s2 = "Arithmetic"
print(s1 + s2)

# - 减法运算符
print(y - x)

# 此外，“-”除了可以作为减法运算符之外，还可以作为求负的运算符。请看如下代码：
# 定义变量x，其值为-5.0
x = -5.0
# 将x求负，其值变成5.0
x = -x
print(x)
# 但单目运算符“+”则不对操作数做任何改变，例如如下代码：
# 纯文本复制
# 定义变量y，其值为-5.0
y = -5.0
# y值依然是-5.0
y = +y
print(y)

# 运算符除了在数字之间进行数值运算，还可以作为字符串的连接运算符，表示将 N 个字符串连接起来
repeat = "repeat "
print(repeat * 5)

# / 和 // 除法运算符
# Python 的除法运算符有两个：“/”表示普通除法，使用它除出来的结果与平常数学计算的结果是相同的（即除不尽时，会产生小数部分）；
# 而“//”表示整除，使用它除出来的结果只有整数部分，小数部分将会被舍弃。
#
# 记住，在 Python 3.x 中，除法运算的结果都是浮点类型。
print("------------------- / 和 // 除法运算符 -------------------")
print("19/4的结果是:", 19 / 4)
print("19//4的结果是:", 19 // 4)
aa = 15.2
bb = 3.1
# aa / bb的值将是1.67741935483871
print("aa/bb的值是:", aa / bb)
# aa // bb值将是1.0
print("aa//bb的值是:", aa // bb)

# % 求余运算符
#
# Python 不要求求余运算符的两个操作数都是整数，Python 的求余运算符完全支持对浮点数求余。求余运算的结果不一定总是整数，它是使用第
# 一个操作数来除以第二个操作数，得到一个整除的结果后剩下的值就是余数。


# ** 乘方运算符
#
# Python 支持使用“**”作为乘方运算符，这是一个使用非常方便的运算符。由于开方其实是乘方的逆运算，因此实际上使用“**”也可进行开方运算。
x = 2
y = 3
print(2 ** 3)

print("------------------- 赋值运算符 -------------------")
a = 1
b = 2
a += b
print("a+b=", a)  # 1+2=3
a -= b
print("a-b=", a)  # 3-2=1
a *= b
print("a*b=", a)  # 1*2=2
a /= b
print("a/b=", a)  # 2/2=1.0
a %= b
print("a%b=", a)  # 1%2=1.0
c = 0
d = 2
c &= d
print("c&d=", c)  # 0&2=0
c |= d
print("c|d=", c)  # 0|2=2

print("------------------- 位运算符详解 -------------------")

# 位运算符通常在图形、图像处理和创建设备驱动等底层开发中使用。使用位运算符可以直接操作数值的原始 bit 位，尤其是在使用自定义的协议进行
# 通信时，使用位运算符对原始数据进行编码和解码也非常有效。
#
# 位运算符的操作对象是整数类型，它会把数字看做对应的二进制数来进行计算。
#
#  位运算符	说 明	    使用形式	举 例
#   &     	按位与	    a & b	    4 & 5
#   |	    按位或	    a | b	    4 | 5
#   ^     	按位异或	a ^ b	    4 ^ 5
#   ~	    按位取反	~a	        ~4
#   <<	    按位左移	a << b	    4 << 2，表示数字 4 按位左移 2 位
#   >>	    按位右移	a >> b	    4 >> 2，表示数字 4 按位右移 2 位
#
# 其实数据存储在内存中都是存储的二进制，二进制又可分为原码、反码、补码。最终存储在内存中的是“补码”
# 个正数的原码、反码、补码都是它的二进制表现形式。(无符号数没有原码、反码和补码一说。只有带符号数才存在不同的编码方式。)
#
# 例如：9 == int == 4个字节 == 1个字节等于8位 == 整形有32位
# 正数的原码：
# 0000 0000 0000 0000 0000 0000 0000 1001
# 正数的反码就是正数的原码：
# 0000 0000 0000 0000 0000 0000 0000 1001
# 正数的补码也是整数的原码：
# 0000 0000 0000 0000 0000 0000 0000 1001
#
# 二进制的第一位是符号位，0代表整数，1代表负数。
# 一个负数的原码是首位为1的二进制数。反码是符号位不变，其他位取反。补码是反码加1
# 例如：-9
# 原码为首位为1的二进制数：
# 1000 0000 0000 0000 0000 0000 0000 1001
# 反码为符号位不变，其他位取反：
# 1111 1111 1111 1111 1111 1111 1111 0110
# 补码是反码加1：
# 1111 1111 1111 1111 1111 1111 1111 0111
#
# 为什么会有原码反码补码？
# 由于最高位是符号位，如果是0就代表正数，1就代表是负数。
# 那么直接存储原码，计算机在计算的时候还需要先判断最高位才能计算，效率比较低
# 为了方便计算机计算，所以有了反码和补码，然后计算机就不需要判断符号位了，只做加法运算就可以了。
# 计算十进制的表达式：1 - 1 = 0
#
# 1 - 1 == 1 + (-1)
#  0000 0001(原码)
# +1000 0001(原码)
# ----------------
#  1000 0010(原码) == -2
#
# 如果用原码表示，让符号位参与计算，显然对于减法来说是不正确的。这也是计算机内部不以原码表示的原因。
#
# 为了解决原码做减法的问题，出现了反码：
#
# 1 - 1 == 1 + (-1)
#  0000 0001(反码)
# +1111 1110(反码)
# ----------------
#  1111 1111(反码) 转成原码 -> 1000 0000 == -0
#
#  发现用反码计算减法，结果的真值部分是正确的，而唯一的问题其实就出现在“0”这个特殊的数值上，虽然人们理解上+0(0000 0000) 和 -0(1 0000 0000)
#  是一样的，但是0带上符号是没有任何意义的。而且0的编码有两个。
#
# 通常我们用最高的有效位来表示数的符号（当用8位来表示一个整数时，第8位即为最高有效位，当用16位来表示一个整数时，第16位即为最高有效位。）0表示
# 正号、1表示负号，这种正负号数字化的机内表示形式就称为“机器数”，而相应的机器外部用正负号表示的数称为“真值”。将一个真值表示成二进制字串的机器
# 数的过程就称为编码。
#
# 于是补码出现了，解决了0的符号问题以及两个编码的问题，0的编码就只有+0，-0已经等于-128了。
#
# 1 - 1 == 1 + (-1)
#  0000 0001(补码)
# +1111 1111(补码)
# ----------------
# 10000 0000(补码)
# 第一位溢出后转成原码 -> 0000 0000 == 0
#
# 5 - 4
# 0000 0101 1*2^2 + 0*2^1 + 0*2^0
# 1000 0100 -4 原码
# 1111 1011 -4 反码
# 1111 1110 -4 补码

print("------------------- 位运算符详解 -------------------")

# 较运算符，也成关系运算符，用于对常量、变量或表达式的结果进行大小、真假等比较，如果比较结果为真，则返回 True；反之，则返回 False。
#
#   比较运算符	                            功能
#       >	        大于，如果运算符前面的值大于后面的值，则返回 True；否则返回 False
#       >=	        大于或等于，如果运算符前面的值大于或等于后面的值，则返回 True；否则返回 False
#       <	        小于，如果运算符前面的值小于后面的值，则返回 True；否则返回 False
#       <=	        小于或等于，如果运算符前面的值小于或等于后面的值，则返回 True；否则返回 False
#       ==	        等于，如果运算符前面的值等于后面的值，则返回 True；否则返回 False
#       !=	        不等于，如果运算符前面的值不等于后面的值，则返回 True；否则返回 False
#       is	        判断两个变量所引用的对象是否相同，如果相同则返回 True
#       is not	    判断两个变量所引用的对象是否不相同，如果不相同则返回 True
print("5是否大于 4：", 5 > 4)
print("3的4次方是否大于等于90.0：", 3 ** 4 >= 90)
print("20是否大于等于20.0：", 20 >= 20.0)
print("5和5.0是否相等：", 5 == 5.0)
print("True和False是否相等：", True == False)

# 比较运算符 == 和 is 的区别
# 初学 Python，大家可能对 is 比较陌生，很多人会误将它和 == 的功能混为一谈，但其实 is 与 == 有本质上的区别，完全不是一码事儿。
# == 用来比较两个变量的值是否相等，而 is 则用来比对两个变量引用的是否是同一个对象
print("------------------- 比较运算符 == 和 is 的区别 -------------------")
print("python 中的 == 类似 Java 中的 equals ")
a = time.gmtime()
b = time.gmtime()
print(a == b)  # a和b两个时间相等，输出True
print(a is b)  # a和b不是同一个对象，输出False

# 上面代码中 a、b 两个变量都代表当前系统时间，因此 a、b 两个变量的时间值是相等的（代码运行速度很快，能保证是同一时间），故程序
# 使用“==”判断返回 True。但由于 a、b 两个变量分别引用不同的对象（每次调用 gmtime() 函数都返回不同的对象），因此a is b返回 False。
#
# 么，如何判断两个变量是否属于一个对象呢？Python 提供了一个全局的 id() 函数，它可以用来判断变量所引用的对象的内存地址（相当于对象
# 在计算机内存中存储位置的门牌号），如果两个对象所在的内存地址相同（相当于它们住在同一个房间内，计算机同一块内存在任一时刻只能存放一个对象），则说明这两个对象其实是同一个对象。
#
# 由此可见，is 判断其实就是要求通过 id() 函数计算两个对象时返回相同的地址。例如，使用 id() 函数判断上面的 a、b 两个变量：
print(id(a))
print(id(b))

a = 'hello'
b = 'hello'
print(a is b)

# 逻辑运算符是对真和假两种布尔值进行运算（操作 bool 类型的变量、常量或表达式），逻辑运算的返回值也是 bool 类型值。
#
# Python 中的逻辑运算符主要包括 and（逻辑与）、or（逻辑或）以及 not（逻辑非），它们的具体用法和功能如表 1 所示。
#
#                                表 1 Python 逻辑运算符及功能
#  逻辑运算符	       含义	        基本格式	                        功能
#     and	    逻辑与（简称“与”）	a and b	    有 2 个操作数 a 和 b，只有它们都是 True 时，才返回 True，否则返回 False。
#     or	    逻辑或（简称“或”）	a or b	    有 2 个操作数 a 和 b ，只有它们都是 False 时，才返回 False，否则返回 True。
#     not	    逻辑非（简称“非”）	not a	    只需要 1 个操作数 a，如果 a 的值为 True，则返回 False；反之，如果 a 的值为 False，则返回 True。

print("------------------- 逻辑运算符 -------------------")
# 直接对False求非运算，将返回True
print(not False)
# 5>3返回True，20.0大于10，因此结果返回True
print(5 > 3 and 20.0 > 10)
# 4>=5返回False，"c">"a"返回True。求或后返回True
print(4 >= 5 or "c" > "a")

bookName = "C语言中文网Python"
price = 99
version = "正式版"

# 确保符号优先级
if bookName.endswith('Python') and (price < 50 or version == "正式版"):
    print("打算购买这套Python教程")
else:
    print("不购买！")

# Python 可通过 if 语句来实现三目运算符的功能，因此可以近似地把这种 if 语句当成三目运算符。作为三目运算符的 if 语句的语法格式如下：
#
#       True_statements if expression else False_statements
#
# 三目运算符的规则是：先对逻辑表达式 expression 求值，如果逻辑表达式返回 True，则执行并返回 True_statements 的值；如果逻辑表达式返
# 回 False，则执行并返回 False_statements 的值。看如下代码

print("------------------- 逻辑运算符 -------------------")

a = 5
b = 3
st = "a大于b" if a > b else "a不大于b"
# 输出"a大于b"
print(st)

# Python 允许在三目运算符的 True_statements 或 False_statements 中放置多条语句。Python 主要支持以下两种放置方式：
# 多条语句以英文逗号隔开：每条语句都会执行，程序返回多条语句的返回值组成的元组。
# 多条语句以英文分号隔开：每条语句都会执行，程序只返回第一条语句的返回值。

# 第一个返回值部分使用两条语句，逗号隔开
st = print("hello"), 'a大于b' if a > b else "a不大于b"
print(st)

# 上面程序中 True_statements 为 print("hello")，'a大于b'，这两条语句都会执行，程序将会返回这两条语句的返回值组成的元组。
# 由于 print() 函数没有返回值，相当于它的返回值是 None。
#
# 如果将上面语句中的逗号改为分号，将逗号之后的语句改为赋值语句，即写成如下形式：

# 第一个返回值部分使用两条语句，分号隔开，如果将上面语句中的逗号改为分号，将逗号之后的语句改为赋值语句，即写成如下形式：
st = print("crazyit");
x = 20 if a > b else "a不大于b"
print(st)
print(x)
